package org.whatever.aha.zjut.platform.controller.project;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.stp.StpUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.apache.ibatis.jdbc.Null;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.whatever.aha.zjut.base.constant.AuthConst;
import org.whatever.aha.zjut.base.constant.ErrorCode;
import org.whatever.aha.zjut.base.constant.StatusConstant;
import org.whatever.aha.zjut.base.dto.AjaxResult;
import org.whatever.aha.zjut.base.exception.AppException;
import org.whatever.aha.zjut.platform.annotation.ProjectPermission;
import org.whatever.aha.zjut.platform.annotation.StageLimit;
import org.whatever.aha.zjut.platform.dto.project.ProjectDto;
import org.whatever.aha.zjut.platform.dto.project.ProjectMemberDto;
import org.whatever.aha.zjut.platform.entity.competition.CompetitionStageStatus;
import org.whatever.aha.zjut.platform.entity.project.Project;
import org.whatever.aha.zjut.platform.service.competition.CompetitionService;
import org.whatever.aha.zjut.platform.service.competition.CompetitionStageService;
import org.whatever.aha.zjut.platform.service.competition.CompetitionStageStatusService;
import org.whatever.aha.zjut.platform.service.project.ProjectMemberService;
import org.whatever.aha.zjut.platform.service.project.ProjectReturnLogService;
import org.whatever.aha.zjut.platform.service.project.ProjectService;
import org.whatever.aha.zjut.platform.util.CheckUtil;
import org.whatever.aha.zjut.platform.vo.project.ProjectDetailVo;
import org.whatever.aha.zjut.platform.vo.project.ProjectMemberVo;
import org.whatever.aha.zjut.platform.vo.project.ProjectReturnLogVo;
import org.whatever.aha.zjut.platform.vo.project.ProjectStuRoughVo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Vc
 * @version 1.0
 * @Desc
 * @date 2021/09/14 23:51
 */
@Api(tags = "项目相关操作类")
@RequestMapping("/v1/project")
@RequiredArgsConstructor
@RestController
@Validated
public class ProjectController {
    final ProjectService projectService;
    final ProjectMemberService projectMemberService;
    final CompetitionService competitionService;
    final CompetitionStageStatusService competitionStageStatusService;
    final ProjectReturnLogService projectReturnLogService;
    final CompetitionStageService competitionStageService;

    /**
     * 获取登录用户某个比赛的粗略信息
     *
     * @param compType  竞赛类型|1
     * @param projectStudentStatus   项目状态学生视角(1:待提交、2:已提交3:已退回、4:已完结)|1
     * @param pageNum   页数|1
     * @param pageSize  页大小|10
     */
    @ApiImplicitParams({
            @ApiImplicitParam(name = "compType", value = "竞赛类型", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "projectStudentStatus", value = " 项目状态(1:待提交、2:已提交3:已退回、4:已完结) 学生视角", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "pageNum", value = "页数", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "pageSize", value = "页大小", dataTypeClass = Integer.class)
    })
    @GetMapping("/myProject")
    public AjaxResult<List<ProjectStuRoughVo>> getAllPersonalProjectPageable(@RequestParam(value = "compType") int compType,
                                                                       @RequestParam(value = "projectStudentStatus", required = false) Integer projectStudentStatus,
                                                                       @RequestParam(value = "pageNum", defaultValue = "1") int pageNum,
                                                                       @RequestParam(value = "pageSize", defaultValue = "10") int pageSize) {
        int userId = StpUtil.getLoginIdAsInt();
        return AjaxResult.SUCCESS(projectService.getProjectRoughPageable(userId, compType, projectStudentStatus, (pageNum - 1) * pageSize, pageSize));
    }

    /**
     * 获取项目详细信息
     *
     * @param projectId
     * @return
     */
    @ApiImplicitParam(name = "projectId", value = "项目Id", dataTypeClass = Integer.class)
    @GetMapping("/{projectId}")
    public AjaxResult<ProjectDetailVo> getProjectDetailById(@PathVariable("projectId") int projectId) {
        return AjaxResult.SUCCESS(projectService.getProjectDetailById(projectId));
    }


    /**
     * 新增项目
     *
     * @param projectDto 项目信息
     */
    @PostMapping("/addProject/{compId}/{stageId}")
    public AjaxResult<Integer> addProject(@PathVariable("compId")int compId,@PathVariable("stageId")int stageId, @RequestBody @Validated ProjectDto projectDto) {
        CompetitionStageStatus singleCompStageStatus = competitionStageStatusService.getSingleCompStageStatus(stageId, 1);
        CheckUtil.checkTimeLimit(singleCompStageStatus.getStatusStartTime(), singleCompStageStatus.getStatusEndTime());
        int userId = StpUtil.getLoginIdAsInt();
        CheckUtil.checkProjectMember(projectDto.getMemberDtos(), new ArrayList<>(), new ArrayList<>(), ((int)competitionService.getMemberLimit(compId)-1), userId);
        return AjaxResult.SUCCESS(projectService.addProjectAndAuthor(projectDto, userId,compId,stageId));
    }

    /**
     * 修改项目信息
     *
     *
     * @param projectDto 修改的项目信息
     * @param projectId  项目id
     */
    @ProjectPermission
    @PutMapping("/updateProject")
    public AjaxResult<Integer> updateProjectById(@RequestBody ProjectDto projectDto, @RequestParam("projectId") int projectId,@RequestParam("compId") int compId,@RequestParam("stageId") int stageId){
        //( 提交阶段 && 项目未提交 ) ||  (项目被退回 && 审核阶段)
        CompetitionStageStatus singleSubmitCompStageStatus = competitionStageStatusService.getSingleCompStageStatus(stageId, StatusConstant.COMPETITION_STAGE_STATUS_ORDER_SUBMIT.getCode());
        CompetitionStageStatus singleJudgeCompStageStatus = competitionStageStatusService.getSingleCompStageStatus(stageId, StatusConstant.COMPETITION_STAGE_STATUS_ORDER_JUDGE.getCode());
        CheckUtil.checkStageStatus(singleSubmitCompStageStatus, singleJudgeCompStageStatus, projectService.getProjectStuStatus(projectId));
        int userId = StpUtil.getLoginIdAsInt();
        //项目成员检验
        List<ProjectMemberVo> memberRough = projectMemberService.getMemberRough(projectId);
        List<Integer> memberIds = memberRough.stream().map(ProjectMemberVo::getMemberId).collect(Collectors.toList());
        List<Integer> memberRanks = memberRough.stream().map(ProjectMemberVo::getProjectMemberRank).collect(Collectors.toList());
        CheckUtil.checkProjectMember(projectDto.getMemberDtos(), memberIds, memberRanks, ((int)competitionService.getMemberLimit(compId)-1), userId);
        return AjaxResult.SUCCESS(projectService.updateProjectByProjectId(projectDto, userId, projectId, compId, stageId));
    }


    /**
     * 删除项目
     *
     * @param projectId 项目id
     */
    @ProjectPermission
    @DeleteMapping("/{projectId}")
    public AjaxResult<Object> deleteProjectById(@PathVariable("projectId") int projectId){
        //提交阶段 && 项目未提交
        CompetitionStageStatus singleCompStageStatus = competitionStageStatusService.getSingleCompStageStatus(projectService.getProjectDetailById(projectId).getStageId(),  StatusConstant.COMPETITION_STAGE_STATUS_ORDER_SUBMIT.getCode());
        CheckUtil.checkTimeLimit(singleCompStageStatus.getStatusStartTime(), singleCompStageStatus.getStatusEndTime());
        CheckUtil.checkStuStatus(StatusConstant.PROJECT_STUDENT_STATUS_WAIT_FOR_SUBMIT.getCode(), projectService.getProjectStuStatus(projectId));
        return AjaxResult.SUCCESS(projectService.deleteProjectById(projectId));
    }

    /**
     * 提交项目
     *
     * @param projectId
     * @return
     */
    @ProjectPermission
    @PutMapping("/submitProject/{projectId}")
    public AjaxResult<Integer> submitProject(@PathVariable("projectId")int projectId){
        Integer academyStatus = null;
        Integer schoolStatus = null;
        //( 提交阶段 && 项目未提交 ) ||  (项目被退回 && 审核阶段)
        ProjectDetailVo projectDetailById = projectService.getProjectDetailById(projectId);
        int stageId = projectDetailById.getStageId();
        CompetitionStageStatus singleSubmitCompStageStatus = competitionStageStatusService.getSingleCompStageStatus(stageId, StatusConstant.COMPETITION_STAGE_STATUS_ORDER_SUBMIT.getCode());
        CompetitionStageStatus singleJudgeCompStageStatus = competitionStageStatusService.getSingleCompStageStatus(stageId, StatusConstant.COMPETITION_STAGE_STATUS_ORDER_JUDGE.getCode());
        CheckUtil.checkStageStatus(singleSubmitCompStageStatus, singleJudgeCompStageStatus, projectService.getProjectStuStatus(projectId));
        //如果该比赛不需要院级管理员评审，直接将院级状态设为已推荐,校级置为待审核
        Object compId = projectService.getCompIdByProjectId(projectId);
        if(StatusConstant.COMPETITION_NOT_NEED_ACADEMY_REC.getCode().equals(competitionService.getCompetitionById((int) compId).getNeedAcademyRec())){
            academyStatus = StatusConstant.PROJECT_STATUS_ACADEMY_VERSION_ALREADY_JUDGED.getCode();
            schoolStatus = StatusConstant.PROJECT_STATUS_SCHOOL_VERSION_WAIT_FOR_JUDGE.getCode();
        }else{
            academyStatus = StatusConstant.PROJECT_STATUS_ACADEMY_VERSION_WAIT_FOR_JUDGE.getCode();
        }
        //校团委项目直接给校级管理员审核
        if (projectDetailById.getProjectSchoolRec()) {
            schoolStatus = StatusConstant.PROJECT_STATUS_SCHOOL_VERSION_WAIT_FOR_JUDGE.getCode();
        }
        return AjaxResult.SUCCESS(projectService.submitProject(projectId, academyStatus, schoolStatus));
    }

    /**
     * 退回修改项目提交
     *
     * @param projectId
     * @return
     */
    @ProjectPermission
    @StageLimit({"submit", "judge"})
    @PutMapping("/submitReturnedProject/{stageId}/{projectId}")
    public AjaxResult<Integer> submitReturnedProject(@PathVariable("projectId")int projectId, @PathVariable("stageId")int stageId){
        //项目状态必须为退回修改，且提交时间为提交与审核阶段
        if(!StatusConstant.PROJECT_STUDENT_STATUS_RETURN.getCode().equals(projectService.getProjectStuStatus(projectId))){
            throw new AppException(ErrorCode.ILLEGAL_SUBMIT_OPERATION);
        }
        return AjaxResult.SUCCESS(projectService.submitReturnedProject(projectId, stageId));
    }

    /**
     * 获取退回修改项目的审批信息
     *
     * @param projectId
     * @param stageId
     * @return
     */
    @GetMapping("/getReturnedOA/{stageId}/{projectId}")
    public AjaxResult<ProjectReturnLogVo> getReturnedOA(@PathVariable("projectId")int projectId, @PathVariable("stageId")int stageId){
        return AjaxResult.SUCCESS(projectService.getReturnedOA(projectId, stageId));
    }

    /**
     * 根据竞赛阶段id获取distinct竞赛标签信息
     *
     * @param compId
     * @param stageId
     * @return
     */
    @GetMapping("/getDistinctCompTags/{compId}/{stageId}")
    public Object getDistinctCompTags(@PathVariable("compId") int compId, @PathVariable("stageId") int stageId){
        return AjaxResult.SUCCESS(projectService.getDistinctCompTags(compId, stageId));
    }

    /**
     * 学生项目进入下一个阶段
     *
     * @param projectId
     * @param stageId  当前stageId （暗指复赛）
     * @return
     */
    @StageLimit({"submit"})
    @PutMapping("/enterNextStage/{projectId}/{stageId}")
    public AjaxResult<Integer> projectEnterNextStage(@PathVariable("projectId") int projectId, @PathVariable("stageId") int stageId){
        //阶段ID要在现有的阶段ID之前 && 同一届比赛 && 项目可进入下一阶段标志 && 负责人 && 复赛提交阶段
        Project project = projectService.getProjectById(projectId);
        if(project.getStageId() <= stageId){
            throw new AppException(ErrorCode.COMPETITION_STAGE_FOR_ENTER_NEXT_STAGE_ILLEGAL);
        }
        if(project.getCompId() != competitionStageService.getCompIdByStageId(stageId)){
            throw new AppException(ErrorCode.NOT_SAME_COMPETITION);
        }
        if(!StatusConstant.PROJECT_PERMITTED_ENTER_NEXT_STAGE.getCode().equals(project.getProjectEnterNextStage())){
            throw new AppException(ErrorCode.PROJECT_NOT_PERMIT_TO_ENTER_NEXT_STAGE);
        }
        if(StpUtil.getLoginIdAsInt() != (project.getProjectLeaderId())){
            throw new AppException(ErrorCode.OPERATION_NOT_AUTHORIZED);
        }
        return AjaxResult.SUCCESS(projectService.projectEnterNextStage(projectId, stageId));
    }
}
